package online.inote.naruto.utils;

import com.alibaba.fastjson.JSON;
import lombok.Data;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @description MD5工具类(密码加密)
 * @author XQF.Sui
 * @date 2021/08/14 15:59
 */
public class MdFiveUtils {

  private static final String SALT =
      DigestUtils.md5DigestAsHex("NARUTO-SECURITY".getBytes(StandardCharsets.UTF_8));
  private static final String EMPTY_JSON = "{}";

  public static String encrypt(String data) {
    return DigestUtils.md5DigestAsHex((SALT + data).getBytes(StandardCharsets.UTF_8));
  }

  public static String digest(DigestWorker worker) {
    return digest(
        worker.nonce, worker.url, worker.timestamp, worker.token, worker.params, worker.arguments);
  }

  public static String digest(
      final String nonce,
      final String url,
      final Long timestamp,
      final String token,
      final Object... arguments) {
    return digest(nonce, url, timestamp, token, null, arguments);
  }

  public static String digest(
      final String nonce,
      final String url,
      final Long timestamp,
      final String token,
      final String params,
      final Object... arguments) {

    Assert.notBlank(nonce, "nonce不能为空");
    Assert.notBlank(url, "url不能为空");

    StringBuilder sb = new StringBuilder(SALT + nonce + url);

    if (!Objects.isNull(timestamp)) {
      sb.append(timestamp);
    }

    if (!Objects.isNull(token)) {
      sb.append(token);
    }

    if (StringUtils.isNotBlank(params) && !StringUtils.equals(params, EMPTY_JSON)) {
      sb.append(params);
    }

    sb.append(argumentsSort(arguments));

    return DigestUtils.md5DigestAsHex(sb.toString().getBytes(StandardCharsets.UTF_8));
  }

  private static String argumentsSort(final Object... arguments) {
    if (arguments != null && arguments.length > 0) {
      List<Object> list =
          Arrays.stream(arguments)
              .sorted(Comparator.comparing(Object::hashCode))
              .collect(Collectors.toList());

      char[] chars = JSON.toJSONString(list).toCharArray();
      Arrays.sort(chars);
      return Arrays.toString(chars);
    }

    return "";
  }

  public static DigestWorker builder() {
    return new DigestWorker();
  }

  @Data
  public static class DigestWorker {
    private String nonce;
    private String url;
    private Long timestamp;
    private String token;
    private String params;
    private Object[] arguments;

    public DigestWorker nonce(String nonce) {
      this.nonce = nonce;
      return this;
    }

    public DigestWorker url(String url) {
      this.url = url;
      return this;
    }

    public DigestWorker timestamp(Long timestamp) {
      this.timestamp = timestamp;
      return this;
    }

    public DigestWorker token(String token) {
      this.token = token;
      return this;
    }

    public DigestWorker params(String params) {
      this.params = params;
      return this;
    }

    public DigestWorker arguments(Object... arguments) {
      this.arguments = arguments;
      return this;
    }

    public String execute() {
      return MdFiveUtils.digest(this);
    }
  }
}
